package com.appspot.bibtable.servlet;

import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.util.logging.Logger;

import javax.jdo.JDOObjectNotFoundException;
import javax.jdo.JDOUserCallbackException;
import javax.jdo.PersistenceManager;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.appspot.bibtable.PMF;
import com.appspot.bibtable.model.Reference;
import com.appspot.bibtable.model.ReferenceEntity;
import com.appspot.bibtable.model.UserInfo;
import com.appspot.bibtable.model.annotation.Input;
import com.appspot.bibtable.util.ReflectionUtility;
import com.appspot.bibtable.view.html.HtmlTemplate;
import com.appspot.bibtable.view.html.ReferenceInputTable;
import com.appspot.bibtable.view.html.ReferenceTable;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;

public class EditItemServlet extends PathQueryHttpServlet
{
	private static final Logger logger = Logger.getLogger(EditItemServlet.class.getName());

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{
		UserService service = UserServiceFactory.getUserService();
		if (UserInfo.getUserInfoOf(service.getCurrentUser()) != null)
		{
			Key key = getKey(request);
			if (key == null)
			{
				response.sendError(HttpServletResponse.SC_NOT_FOUND);
				return;
			}

			response.setCharacterEncoding("UTF-8");
			PrintWriter writer = response.getWriter();

			PersistenceManager manager = PMF.get().getPersistenceManager();
			try
			{
				ReferenceEntity entity = manager.getObjectById(ReferenceEntity.class, key);

				HtmlTemplate template = new HtmlTemplate();
				ReferenceTable table = new ReferenceInputTable();
				table.setPersistenceManager(manager);
				table.setId("reference-info");
				table.setDocumentRequired(true);

				template.setTitle("Edit " + entity.getTitle());
				template.setRequest(request);
				template.startDocument(writer);
				template.startContent(writer);
				writer.write("<form action=\"" + request.getRequestURI() + "\" method=\"post\">");
				table.startTable(writer);
				table.addReference(entity, writer);
				table.endTable(writer);
				writer.write("<div id=\"item-query-buttons\">");
				writer.write("<input type=\"hidden\" name=\"redirect\" value=\"detail\" />");
				writer.write("<input type=\"reset\" />");
				writer.write("<input type=\"submit\" />");
				writer.write("</div>");
				writer.write("</form>");
				writer.println();
				template.endContent(writer);
				template.endDocument(writer);
			}
			catch (JDOObjectNotFoundException ex)
			{
				response.sendError(HttpServletResponse.SC_NOT_FOUND);
			}
			finally
			{
				manager.close();
			}
		}
		else
		{
			logger.warning("Item edit request from non-registered user (" + request.getRemoteAddr() + ").");
			response.sendError(HttpServletResponse.SC_FORBIDDEN);
		}
	}

	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{
		UserService service = UserServiceFactory.getUserService();
		if (UserInfo.getUserInfoOf(service.getCurrentUser()) != null)
		{
			Key key = getKey(request);
			if (key == null)
			{
				response.sendError(HttpServletResponse.SC_NOT_FOUND);
				return;
			}

			PersistenceManager manager = PMF.get().getPersistenceManager();
			try
			{
				ReferenceEntity entity = manager.getObjectById(ReferenceEntity.class, key);
				Reference reference = entity.getReference();
				Field[] fields = ReflectionUtility.getAllFields(reference.getClass(), true);
				for (Field field : fields)
				{
					Input input = field.getAnnotation(Input.class);
					if (input == null)
					{
						continue;
					}
					String value = request.getParameter(field.getName());
					if (value != null)
					{
						reference.setValue(field, value);
					}
				}

				Field[] entityFields = ReflectionUtility.getAllFields(ReferenceEntity.class, false);
				for (Field field : entityFields)
				{
					Input input = field.getAnnotation(Input.class);
					if (input == null)
					{
						continue;
					}
					String value = request.getParameter(field.getName());
					if (value != null)
					{
						entity.setValue(field, value);
					}
				}

				entity.update();
				manager.makePersistent(entity);
				logger.info("Entity edit (key:" + key + ").");
			}
			catch (JDOUserCallbackException ex)
			{
				logger.warning(ex.getMessage());
			}
			finally
			{
				manager.close();
			}

			String redirect = request.getParameter("redirect");
			if (redirect != null)
			{
				response.sendRedirect("/" + redirect + "/" + KeyFactory.keyToString(key));
			}
		}
		else
		{
			logger.warning("New item request from non-registered user (" + request.getRemoteAddr() + ").");
			response.sendError(HttpServletResponse.SC_FORBIDDEN);
		}
	}
}
